`include "mycpu.h"

module wb_stage(
    input                           clk           ,
    input                           reset         ,
    //allowin
    output                          ws_allowin    ,
    //from ms
    input                           ms_to_ws_valid,
    input  [`MS_TO_WS_BUS_WD -1:0]  ms_to_ws_bus  ,
    //to rf: for write back
    output [`WS_TO_RF_BUS_WD -1:0]  ws_to_rf_bus  ,
    //trace debug interface
    output [31:0] debug_wb_pc     ,
    output [ 3:0] debug_wb_rf_wen ,
    output [ 4:0] debug_wb_rf_wnum,
    output [31:0] debug_wb_rf_wdata,
    //add block and bypass code
    output [37:0] wb_to_id_byp_block,
    //Ertn
    output [31:0] csr_epc ,
    output [0: 0] inst_ertn,
    output [31:0] csr_eentry,
    //Int
    /*We should tell this 'ws_has_int' from 'has_int'. 'Ws_has_int' means
    this instruction has tag 'int', 'has_int' means the instruction which
    is in the ID pipeline has int*/   
    output [0: 0] has_int,
    output [0: 0] ws_has_int,
    output [0: 0] ws_ertn,
    output [0: 0] ws_ex_o,
    output [0: 0] ws_inst_csrrd ,
    output [0: 0] ws_inst_csrwr,
    output [0: 0] ws_inst_csrxchg  
);

assign ws_inst_csrrd = inst_csrrd & ws_valid;
assign ws_inst_csrwr = inst_csrwr & ws_valid;
assign ws_inst_csrxchg = inst_csrxchg & ws_valid;

reg         ws_valid;
wire        ws_ready_go;

reg [`MS_TO_WS_BUS_WD -1:0] ms_to_ws_bus_r;
wire        ws_gr_we;
wire [ 4:0] ws_dest;
wire [31:0] ws_final_result;
wire [31:0] ws_pc;

//Lab 8 add code and signals!!!
wire [31:0] ws_rj_value;
wire [31:0] ws_rkd_value;
wire [31:0] ws_inst;
wire [0 :0] ertn_reflush = inst_ertn && ws_valid;

wire [0: 0] inst_csrrd;
wire [0: 0] inst_csrwr;
wire [0: 0] inst_csrxchg;
wire [0: 0] inst_syscall;



wire [5: 0] wb_ecode;
wire [8: 0] wb_esubcode;


assign {wb_esubcode    ,  //196:188
        wb_ecode       ,  //187:182
        inst_syscall   ,  //181:181
        ws_has_int     ,  //180:180
        ws_ex          ,  //179:179
        inst_ertn      ,  //169:169
        ws_inst        ,  //168:137
        inst_csrxchg   ,  //136:136
        inst_csrwr     ,  //135:135
        inst_csrrd     ,  //134:134
        ws_rkd_value   ,  //133:102
        ws_rj_value    ,  //101:70
        ws_gr_we       ,  //69:69
        ws_dest        ,  //68:64
        ws_final_result,  //63:32
        ws_pc             //31:0
       } = ms_to_ws_bus_r;

assign ws_ertn = inst_ertn && ws_valid;

assign ws_ex_o = ws_ex && ws_valid;

wire        rf_we;
wire [4 :0] rf_waddr;
wire [31:0] rf_wdata;
assign ws_to_rf_bus = {rf_we   ,  //37:37
                       rf_waddr,  //36:32
                       rf_wdata   //31:0
                      };

assign ws_ready_go = 1'b1;
assign ws_allowin  = !ws_valid || ws_ready_go;
always @(posedge clk) begin
    if (reset) begin
        ws_valid <= 1'b0;
    end
    else if (ws_allowin) begin
        ws_valid <= ms_to_ws_valid;
    end

    if (ms_to_ws_valid && ws_allowin) begin
        ms_to_ws_bus_r <= ms_to_ws_bus;
    end
end

assign rf_we    = ws_gr_we&&ws_valid;
assign rf_waddr = ws_dest;
//If csrrX, we just need to write the old value into the registers
assign rf_wdata = (inst_csrrd | inst_csrwr | inst_csrxchg)? csr_rvalue : ws_final_result;

// debug info generate
assign debug_wb_pc       = ws_pc;
assign debug_wb_rf_wen   = {4{rf_we}};
assign debug_wb_rf_wnum  = ws_dest;
assign debug_wb_rf_wdata = rf_wdata;

//add block and bypass code
wire [4:0] wb_to_id_dest;
wire [0:0] wb_wen;
wire [31:0] wb_to_id_res;

assign wb_to_id_dest = ws_dest;
assign wb_wen        = ws_gr_we && ws_valid;
assign wb_to_id_res  = rf_wdata;

assign wb_to_id_byp_block = {wb_wen,wb_to_id_dest,rf_wdata};

//Lab 8 add code
wire [13:0] csr_num;
wire [0: 0] csr_we;
wire [31:0] csr_wmask;
wire [31:0] csr_wvalue;
wire [31:0] csr_rvalue;
wire [7:0]  hw_int_in;
wire [0:0]  ipi_int_in;
//Output Control Registers
wire [31:0] csr_crmd  ;
wire [31:0] csr_prmd  ;
wire [31:0] csr_era   ;
wire [31:0] csr_save0 ;
wire [31:0] csr_save1 ;
wire [31:0] csr_save2 ;
wire [31:0] csr_save3 ;
wire [31:0] csr_ecfg  ;


assign csr_we    = (inst_csrxchg | inst_csrwr) & ws_valid & ~ws_ex;
assign csr_num   = ws_inst[23:10];
assign csr_wmask = (inst_csrwr)? 32'hffffffff : ws_rj_value;       //If the inst is csr_wmask, we set the mask all bits 1
assign csr_wvalue= ws_rkd_value;
assign hw_int_in = 8'b0;   //Initialize all 0
assign ipi_int_in= 1'b0;

csrr u_csrr(
    .clk(clk),
    .reset(reset),
    .wb_ex(ws_ex_o),
    .hw_int_in(hw_int_in),
    .ipi_int_in(ipi_int_in),
    .ws_pc(ws_pc),
    .ertn_reflush(ertn_reflush),
    .csr_num(csr_num),
    .csr_we(csr_we),
    .csr_wmask(csr_wmask),
    .csr_wvalue(csr_wvalue),
    .wb_ecode(wb_ecode),
    .wb_esubcode(wb_esubcode),
    .csr_rvalue(csr_rvalue),
    //If this is int
    .has_int(has_int),
    //Control registers
    .csr_crmd(csr_crmd),
    .csr_prmd(csr_prmd),
    .csr_era(csr_era),
    .csr_ecfg(csr_ecfg),
    .csr_eentry(csr_eentry),
    .csr_save0(csr_save0),
    .csr_save1(csr_save1),
    .csr_save2(csr_save2),
    .csr_save3(csr_save3)
);

//EPC
assign csr_epc = {32{ws_valid}} & csr_era;

endmodule
